#include <thread>
#include <functional>
#include <cstdlib>
#include <string>
#include <sstream>
#include "../../include/wke.h"
#include "CNewOnlineMiniBlink.h"
#include "../SetupByMiniBlink/SetupByMiniBlink.h"
using namespace std;
UINT WM_UI_INVOKE = WM_USER + 0x900;
extern wstring g_NodeDir;
void UIInvoke(function<void()> func) {	
	SendMessage(g_hWnd, WM_UI_INVOKE, (WPARAM)&func, NULL);
}
jsValue JS_CALL JsNativeFunctionDownload(jsExecState es) {
	if (jsArgCount(es) < 2||
		jsTypeOf(jsArg(es, 0))!= jsType::JSTYPE_STRING|| 
		jsTypeOf(jsArg(es, 1)) != jsType::JSTYPE_STRING||
		(jsArgCount(es) > 2 && jsTypeOf(jsArg(es, 2)) != jsType::JSTYPE_FUNCTION)
		) {
		return jsUndefined();
	}
	const char* url = jsToString(es, jsArg(es, 0));
	const wchar_t* savePath= jsToStringW(es, jsArg(es, 1));
	wstring savePathStr(savePath);
	if (savePathStr.find('\\')==wstring::npos&&savePathStr.find('/')==wstring::npos)
	{
		savePathStr.clear();
		savePathStr.append(g_NodeDir).append(L"\\").append(savePath);
	}

	jsValue postFunction = jsArg(es,2);

	string globalPostFunctionNameStr("__download_post_");
	char randBuffer[9] = { 0 };
	_itoa(rand(), randBuffer, 10);
	globalPostFunctionNameStr.append(randBuffer);
	jsSetGlobal(es, globalPostFunctionNameStr.c_str(), postFunction);

	jsValue globalPostFunction = jsGetGlobal(es, globalPostFunctionNameStr.c_str());

	function<void(DWORD64, DWORD64)> post = [globalPostFunctionNameStr](DWORD64 totalSize, DWORD64 currentSize) {
		UIInvoke([totalSize,currentSize, globalPostFunctionNameStr]() {
			jsExecState es = wkeGlobalExec((wkeWebView)g_pOnlineMiniBlink->GetWebView());
			jsValue args[2];
			args[0] = jsString(es,to_string(totalSize).c_str());
			args[1] = jsString(es, to_string(currentSize).c_str());
			jsValue postFunction = jsGetGlobal(es, globalPostFunctionNameStr.c_str());
			jsCall(es, postFunction, NULL, args, 2);
			if (currentSize == totalSize) {
				jsSetGlobal(es, globalPostFunctionNameStr.c_str(), jsUndefined());
			}
		});
	};
	thread downloadDataThread(DownloadData,url, savePathStr,post);
	downloadDataThread.detach();
	return jsUndefined();
}
jsValue JS_CALL  JsNativeFunctionExec(jsExecState es) {
	if (jsArgCount(es) < 1 ||jsTypeOf(jsArg(es, 0)) != jsType::JSTYPE_STRING) {
		return jsUndefined();
	}
	const wchar_t* command=jsToStringW(es,jsArg(es, 0));
	wstring commandStr(command);
	if (commandStr.find('\\') == wstring::npos && commandStr.find('/') == wstring::npos)
	{
		commandStr.clear();
		commandStr.append(g_NodeDir).append(L"\\").append(command);
	}

	PROCESS_INFORMATION info = {0};
	STARTUPINFO si = { sizeof(si) };
	auto bCreateProcess=CreateProcess(NULL, (LPWSTR)commandStr.c_str(), NULL, NULL, FALSE, NULL, NULL, NULL, &si, &info);
	if (!bCreateProcess) {
		return jsFalse();
	}
	WaitForSingleObject(info.hProcess, INFINITE);
	return jsTrue();
}
jsValue JS_CALL  JsNativeFunctionQuit(jsExecState es) {
	PostQuitMessage(1);
	return jsUndefined();
}
wkeWebView CNewOnlineMiniBlink::OnCreateWebView(HWND hWnd) {
	wkeWebView webView=COnlineMiniBlink::OnCreateWebView(hWnd);

	jsBindFunction("Download", (jsNativeFunction)JsNativeFunctionDownload, 3);
	jsBindFunction("Exec", (jsNativeFunction)JsNativeFunctionExec, 1);
	jsBindFunction("Quit", (jsNativeFunction)JsNativeFunctionQuit, 0);

	return webView;
}
LRESULT CALLBACK CNewOnlineMiniBlink::OnWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
	if (COnlineMiniBlink::OnWndProc(hWnd, message, wParam, lParam)) {
		return TRUE;
	}
	if (message == WM_UI_INVOKE) {
		function<void()>* func = (function<void()>*)wParam;
		(*func)();
		return TRUE;
	}
	return FALSE;
}